import gzip
import os
import struct
import zlib
import sys

from Crypto import Random
from Crypto.Cipher import AES

class AESUtil:

    __BLOCK_SIZE_16 = BLOCK_SIZE_16 = AES.block_size

    @staticmethod
    def encryt(string, key, iv):
        """
        鍔犲瘑鏂囨湰
        :param string: 鏂囨湰
        :param key: 瀵嗛挜
        :param iv: 鍋忕Щ閲�/鍒濆�嬪悜閲�
        :return: 瀵嗘枃
        """

        cipher = AES.new(key, AES.MODE_CBC, iv)
        x = AESUtil.__BLOCK_SIZE_16 - (len(string) % AESUtil.__BLOCK_SIZE_16)
        if x != 0:
            string = string + bytes(chr(x)*x,encoding="utf-8")

        msg = cipher.encrypt(string)

        return msg

    @staticmethod
    def decrypt(en_str, key, iv):
        cipher = AES.new(key, AES.MODE_CBC, iv)

        msg = cipher.decrypt(en_str)
        padding_len = msg[len(msg)-1]
        return msg[0:-padding_len]


def crc32(bytes_obj):
    hashs = 0
    hashs = zlib.crc32(bytes_obj)
    return hashs

def fnv1a_r(oneByte,has):
    return ((oneByte ^ has)*0x1000193) & 0xFFFFFFFF

def getHashCode(data):
    has = 0x811c9dc5
    for i in range(len(data)):
        has = fnv1a_r(data[i],has)
    return has

def gethead(filename,ori_obj):
    type_name = b'zeno'
    type_4 = struct.pack('4s',type_name)

    fota_algo = 0
    algo = struct.pack('<H',fota_algo)

    statinfo=os.stat(filename)
    
    ctime = int(statinfo.st_mtime)
    ct = struct.pack('<I',ctime)
    ct = b'\x00'*(6-len(ct)) + ct 

    app_part_name = b'app'
    apn = struct.pack('16s',app_part_name)

    download_version  = b'1.0.0'
    dv = struct.pack('24s',download_version)

    current_version  = b'00010203040506070809'
    cv = struct.pack('24s',current_version)

    body_crc32 = struct.pack('<I',crc32(ori_obj))

    hash_val = struct.pack('<I',getHashCode(ori_obj))

    raw_size = len(ori_obj)
    raw_size = struct.pack('<I',raw_size)
    com_size = len(ori_obj)
    com_size = struct.pack('<I',com_size)

    head = type_4 + algo + ct + apn + dv + cv + body_crc32 + hash_val + raw_size + com_size
    head = head + struct.pack('<I',crc32(head))
    return head


if __name__ == "__main__":
    if len(sys.argv) != 3:
        sys.exit(1)

    filename = sys.argv[1]
    output_filename = sys.argv[2]
    
    with open(filename, "rb") as f:
        bytes_obj = f.read()
        
        my_head = gethead(filename, bytes_obj)
        
    with open(output_filename, "wb") as f:
        f.write(my_head)
        f.write(bytes_obj)